package com.wyt.cloud.utils.query.duty.handler;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.wyt.cloud.utils.bean.BeanUtil;
import com.wyt.cloud.utils.designpatterns.dutychain.IHandler;
import com.wyt.cloud.utils.query.OrderByDirectionEnum;
import com.wyt.cloud.utils.query.duty.QueryTask;
import com.wyt.cloud.utils.query.reqvo.OrderByParams;
import com.wyt.cloud.utils.query.reqvo.OrderByWithPageRequest;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Order(3)
@Component
public class BuildOrderByHandler<S, T> implements IHandler<QueryTask<S, T>> {

    @Override
    public void execute(QueryTask<S, T> task) {
        buildOrderBy(task.getWrapper(), new BeanWrapperImpl(task.getEntity()));
    }

    /**
     * @param wrapper
     * @param beanWrapper
     */
    private void buildOrderBy(QueryWrapper<T> wrapper, BeanWrapperImpl beanWrapper) {
        List<Field> sourceFields = getFields(beanWrapper);
        for (Field sourceField : sourceFields) {
            if (Modifier.isStatic(sourceField.getModifiers())) {
                continue;
            }
            if (!QueryTask.sortFields.equals(sourceField.getName())) {
                continue;
            }
            buildOrderByParams(wrapper, beanWrapper.getPropertyValue(sourceField.getName()));
        }

    }

    private void buildOrderByParams(QueryWrapper<T> wrapper, Object propertyValue) {
        Map<String, OrderByDirectionEnum> map = (Map<String, OrderByDirectionEnum>) propertyValue;
        if (CollectionUtils.isEmpty(map)) {
            return;
        }
        for (Map.Entry<String, OrderByDirectionEnum> entry : map.entrySet()) {
            wrapper.orderBy(true, OrderByDirectionEnum.ASC.equals(entry.getValue()), BeanUtil.camelToDownLine(entry.getKey()));
        }
    }

    private static List<Field> getFields(BeanWrapperImpl beanWrapper) {
        Class<?> rootClass = beanWrapper.getRootClass();
        List<Field> list = Lists.newArrayList();
        list.addAll(Arrays.asList(rootClass.getDeclaredFields()));
        if (!rootClass.getSuperclass().equals(OrderByParams.class) && !rootClass.getSuperclass().equals(OrderByWithPageRequest.class)) {
            return list;
        }
        Field[] superDeclaredFields = OrderByParams.class.getDeclaredFields();
        if (CollectionUtils.isEmpty(list)) {
            list.addAll(Arrays.asList(superDeclaredFields));
        } else {
            coverSuperFields(beanWrapper, list, superDeclaredFields);
        }
        return list;
    }

    private static void coverSuperFields(BeanWrapperImpl beanWrapper, List<Field> rootFieldlist, Field[] superDeclaredFields) {
        List<String> rootFieldsName = rootFieldlist.stream().map(Field::getName).collect(Collectors.toList());
        for (Field superField : superDeclaredFields) {
            if (CollectionUtils.containsInstance(rootFieldsName, superField.getName())) {
                Object value = beanWrapper.getPropertyValue(superField.getName());
                if (!Objects.isNull(value)) {
                    continue;
                }
            }
            rootFieldlist.add(superField);
        }
    }
}
